/**
 * url地址拼接
 *
 * @param args url
 * @returns
 */
export const joinUrls = (...args: string[]): string => {
  const cleaned = args
    .map(arg => arg.replace(/^\/+|\/+$/g, ""))
    .filter(Boolean);
  if (!cleaned.length) return "/";
  const firstOriginal = args[0] ?? "";
  return firstOriginal === "" || firstOriginal === "/"
    ? `/${cleaned.join("/")}`
    : cleaned.join("/");
};

const recentErrors = new Map<string, number>();

/**
 * Promise.reject注入
 *
 * @param promise new Promise
 * @param handler 注入reject
 * @returns
 */
export function errorReject<T>(
  promise: Promise<T>,
  handler: (reason: any) => void
): Promise<T> {
  promise.catch(reason => {
    const msg = reason?.message ?? String(reason);
    const now = Date.now();
    const lastTime = recentErrors.get(msg);

    // 1秒内相同内容的消息仅返回一条
    if (!lastTime || now - lastTime > 1000) {
      recentErrors.set(msg, now);
      handler(reason);
    }
  });
  return promise;
}

type options = {
  // id键名称
  idKey?: string;
  // fid键名称
  parentIdKey?: string;
  // 重组方法，可以自由组合返回数据格式
  // 该方法会自动忽略设置的children
  // 返回false则不添加到树中
  transform?: (item: any) => any | false;
};

/**
 * 列表转树形结构
 *
 * @param items 源数据
 * @param options 配置
 * @returns
 */
export function arrayToTree(items: any[], options: options = {}): any[] {
  const {
    idKey = "id",
    parentIdKey = "parentId",
    transform = item => ({ ...item })
  } = options;

  const nodeMap = new Map<unknown, any>();
  const childIds = new Set<unknown>();
  const pendingRemoval = new Set<unknown>();

  // 第一次遍历：创建节点并处理转换
  for (const item of items) {
    const originalId = item[idKey];
    const converted = transform(item);

    if (converted === false) {
      pendingRemoval.add(originalId);
      continue;
    }

    nodeMap.set(originalId, {
      ...converted
      //children: []
    });
  }

  // 第二次遍历：建立父子关系并处理排除
  for (const item of items) {
    const originalId = item[idKey];
    const originalParentId = item[parentIdKey];

    // 跳过已标记删除的节点
    if (pendingRemoval.has(originalId)) continue;
    const node = nodeMap.get(originalId);
    if (!node) continue;

    // 处理父节点逻辑
    if (originalParentId) {
      // 父节点需要被删除时，当前节点也标记删除
      if (pendingRemoval.has(originalParentId)) {
        pendingRemoval.add(originalId);
        nodeMap.delete(originalId);
        continue;
      }

      const parent = nodeMap.get(originalParentId);
      if (parent) {
        if (parent.children) {
          parent.children.push(node);
        } else {
          parent.children = [node];
        }
        childIds.add(originalId);
      } else {
        // 父节点不存在且未被标记删除时，标记当前节点为待删除
        pendingRemoval.add(originalId);
        nodeMap.delete(originalId);
      }
    }
  }

  // 最终过滤（保持原始顺序）
  return items
    .filter(item => {
      const id = item[idKey];
      return nodeMap.has(id) && !pendingRemoval.has(id);
    })
    .filter(
      item => item[parentIdKey] == null || !nodeMap.has(item[parentIdKey])
    )
    .map(item => nodeMap.get(item[idKey]));
}
interface TreeLabelNode {
  value: any;
  label: string;
  children?: TreeLabelNode[];
}

/**
 * 获取所有层级value
 *
 * @param nodes 需要查询的树
 * @param targetValue 指定的value
 * @returns
 */
export function findValuePath(nodes: TreeLabelNode[], targetValue: any): any[] {
  // 遍历当前层级节点
  for (const node of nodes) {
    // 直接找到目标节点
    if (node.value === targetValue) {
      return [node.value];
    }

    // 递归搜索子节点
    if (node.children?.length) {
      const childPath = findValuePath(node.children, targetValue);
      if (childPath.length) {
        // 拼接当前节点与子节点路径
        return [node.value, ...childPath];
      }
    }
  }
  return [];
}

/**
 * 生成随机密码
 * @param options 配置选项
 * @returns 生成的随机密码
 */
export function genRandomPassword(options?: {
  length?: number;
  includeNumbers?: boolean;
  includeLowercase?: boolean;
  includeUppercase?: boolean;
  includeSymbols?: boolean;
}): string {
  // 默认配置
  const {
    length = 12,
    includeNumbers = true,
    includeLowercase = true,
    includeUppercase = true,
    includeSymbols = true
  } = options || {};

  // 字符集
  const numbers = "0123456789";
  const lowercase = "abcdefghijklmnopqrstuvwxyz";
  const uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  const symbols = "!@#$%^&*()_+-=[]{}|;:,.<>?";

  // 根据配置构建可用字符集
  let charset = "";
  if (includeNumbers) charset += numbers;
  if (includeLowercase) charset += lowercase;
  if (includeUppercase) charset += uppercase;
  if (includeSymbols) charset += symbols;

  // 如果没有选择任何字符类型，则使用所有类型
  if (charset.length === 0) {
    charset = numbers + lowercase + uppercase + symbols;
  }

  // 生成密码
  let password = "";
  const charsetLength = charset.length;
  const crypto = window.crypto || (window as any).msCrypto; // 兼容IE

  if (crypto?.getRandomValues) {
    // 使用更安全的加密API
    const values = new Uint32Array(length);
    crypto.getRandomValues(values);
    for (let i = 0; i < length; i++) {
      password += charset[values[i] % charsetLength];
    }
  } else {
    // 回退到Math.random (不够安全，但兼容性更好)
    for (let i = 0; i < length; i++) {
      password += charset[Math.floor(Math.random() * charsetLength)];
    }
  }

  return password;
}
